package esms.etonenet.boss1069.listener;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.event.spi.AbstractEvent;
import org.hibernate.event.spi.PostDeleteEvent;
import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;

import com.etonenet.anno.LogEntity;
import com.etonenet.entity.system.SysLog;
import com.etonenet.service.system.security.CustomUser;
import com.etonenet.util.DateUtil;
import com.etonenet.util.SpringUtil;
import com.etonenet.util.StringUtil;

import esms.etonenet.boss1069.enums.syslog.OperType;
import esms.etonenet.boss1069.job.LogJob;

public class EventListener implements PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener {

	private static final long serialVersionUID = 1L;

	@Override
	public void onPostDelete(PostDeleteEvent event) {

		Object obj = event.getEntity();
		if (obj.getClass().isAnnotationPresent(LogEntity.class)) {
			LogJob job = (LogJob) SpringUtil.getBean("logJob");
			job.getLock().lock();
			job.getSysLogs().add(getLog(event, obj, event.getPersister(), OperType.DEL.getValue()));
			job.getLock().unlock();
		}
	}

	@Override
	public void onPostUpdate(PostUpdateEvent event) {

		Object obj = event.getEntity();
		if (obj.getClass().isAnnotationPresent(LogEntity.class)) {
			LogJob job = (LogJob) SpringUtil.getBean("logJob");
			job.getLock().lock();
			job.getSysLogs().add(getLog(event, obj, event.getPersister(), OperType.MODIFY.getValue()));
			job.getLock().unlock();
		}
	}

	@Override
	public void onPostInsert(PostInsertEvent event) {

		Object obj = event.getEntity();
		if (obj.getClass().isAnnotationPresent(LogEntity.class)) {
			LogJob job = (LogJob) SpringUtil.getBean("logJob");
			job.getLock().lock();
			job.getSysLogs().add(getLog(event, obj, event.getPersister(), OperType.INSERT.getValue()));
			job.getLock().unlock();
		}
	}

	public SysLog getLog(AbstractEvent event, Object obj, EntityPersister ep, Integer operType) {

		LogEntity le = obj.getClass().getAnnotation(LogEntity.class);
		List<String> excludePro = new ArrayList<>();
		for (String s : le.excludeProp())
			excludePro.add(s);

		SysLog sl = new SysLog();
		Serializable classId = ep.getIdentifier(obj, event.getSession());
		sl.setClassId(classId.toString());
		sl.setClassName(obj.getClass().getSimpleName() + (le.remark() == null ? "" : "-" + le.remark()));
		sl.setLogTime(DateUtil.getCurrentTimestamp());
		sl.setOper(operType);
		StringBuffer props = new StringBuffer();

		if (OperType.INSERT.getValue().equals(operType)) {

			for (String proName : ep.getPropertyNames()) {
				if (excludePro.contains(proName))
					continue;

				Object value = ep.getPropertyValue(obj, proName);

				if (value != null && StringUtil.isNotEmpty(value.toString())) {
					if (value.getClass().isAnnotationPresent(LogEntity.class))
						value = event.getSession().getEntityPersister(value.getClass().getName(), value)
								.getIdentifier(value, event.getSession());

					props.append(proName + ":" + value + " ");
				}
			}
		} else if (OperType.MODIFY.getValue().equals(operType)) {

			String[] proNames = ep.getPropertyNames();
			Object[] objs = ep.getDatabaseSnapshot(classId, event.getSession());
			for (int i = 0; i < objs.length; i++) {

				Object pro = ep.getPropertyValue(obj, i);
				Object dbPro = objs[i];

				String value = "";
				if (pro != null && StringUtil.isNotEmpty(pro.toString())) {
					if (pro.getClass().isAnnotationPresent(LogEntity.class))
						pro = event.getSession().getEntityPersister(pro.getClass().getName(), pro).getIdentifier(pro,
								event.getSession());
					value = pro.toString();
				}

				String orgValue = "";
				if (dbPro != null && StringUtil.isNotEmpty(dbPro.toString()))
					orgValue = dbPro.toString();

				if (!value.equals(orgValue))
					props.append(proNames[i] + ":" + orgValue + "->" + value + " ");
				else
					props.append(proNames[i] + ":" + orgValue + " ");
			}
		} else if (OperType.DEL.getValue().equals(operType)) {

			String[] proNames = ep.getPropertyNames();
			Object[] objs = ep.getDatabaseSnapshot(classId, event.getSession());
			for (int i = 0; i < objs.length; i++) {
				Object dbPro = objs[i];
				if (dbPro != null && StringUtil.isNotEmpty(dbPro.toString())) {
					props.append(proNames[i] + ":" + dbPro.toString() + " ");
				}
			}
		}

		int maxStr = 1000;
		String proStr = props.toString();
		if (proStr.length() < maxStr)
			maxStr = proStr.length();
		proStr.substring(0, maxStr);
		sl.setProp(proStr);
		sl.setOperUser(((CustomUser) SpringUtil.getUser()).getUser());

		return sl;

	}

	@Override
	public boolean requiresPostCommitHanding(EntityPersister arg0) {
		// TODO Auto-generated method stub
		return false;
	}
}
